home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 1.iso
/
toolbox
/
src
/
exampleCode
/
opengl
/
xlib
/
cylinder2.c
< prev
next >
Wrap
C/C++ Source or Header
|
1996-11-11
|
18KB
|
665 lines
/*
* Copyright (c) 1993-94, Silicon Graphics, Inc.
*
* Permission to use, copy, modify, distribute, and sell this software and
* its documentation for any purpose is hereby granted without fee, provided
* that the name of Silicon Graphics may not be used in any advertising or
* publicity relating to the software without the specific, prior written
* permission of Silicon Graphics.
*
* THE SOFTWARE IS PROVIDED "AS-IS" AND WITHOUT WARRANTY OF ANY KIND,
* EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
* WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
*
* IN NO EVENT SHALL SILICON GRAPHICS BE LIABLE FOR ANY SPECIAL, INCIDENTAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER OR NOT ADVISED OF THE
* POSSIBILITY OF DAMAGE, AND ON ANY THEORY OF LIABILITY, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* OpenGL(TM) is a trademark of Silicon Graphics, Inc.
*/
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <GL/glx.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/keysym.h>
/*
* we'll define our own PI, could get it
* from math.h, but i'm not in the mood
*/
#define M_PI 3.14159265358979323846
/*
* some local functions
*/
void drawScene(void);
void drawcyl(void);
void drawBox(void);
void setMaterial(GLenum, float *, float *, float *, float *);
/*
* define some lighting properties
*/
static float ambient[] = { 0.2, 0.2, 0.2, 1.0 };
static float diffuse[] = { 0.6, 0.6, 0.6, 1.0 };
static float specular[] = { 1.0, 1.0, 1.0, 1.0 };
static float alm[] = { 0.1, 0.1, 0.1, 1};
static float lpos[] = { 0, 0, 100, 0 };
static float shininess[] = { 128.0 };
/*
* define material properties.
*/
static float ambient2[] = { 0.4, 0.0, 0.4, 1.0 };
static float diffuse2[] = { 0.7, 0.0, 0.7, 1.0 };
static float specular2[] = { 1.0, 1.0, 1.0, 1.0 };
float bamat[] = {.4, .4, .4, 1.0};
float bdmat[] = { 0.8, .8, .8, 1.0};
float bsmat[] = { .1, .1, .1, 1.0};
float amat[] = {.1, .1, .2, 0.3};
float dmat[] = { 0.3, .3, .5, 0.3};
float smat[] = { 1.0, 1.0, 1.0, 0.3};
float shin[] = { 128.0 };
float amat2[] = {.1, .1, .1, 0.5};
float dmat2[] = { .3690, .0, .165, 0.5};
float smat2[] = { .8, .8, .8, 0.5};
/*
* the attribute list for the OpenGL visual.
* we only request 1 bit for each color and depth, we get more
* than 1 bit for each, i just put in for the minimum, the
* server should return a visual that meets these requirements or
* better...
*/
static int attributeList[] = {GLX_RGBA, GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 1,
GLX_GREEN_SIZE, 1,
GLX_BLUE_SIZE, 1,
GLX_DEPTH_SIZE, 1,
None };
/*
* the attribute list for the overlay OpenGL visual.
* notice that we define 2 of them, GLX_LEVEL 2 and 1.
* we will try to get an overlay visual (GLX_LEVEL 2). if we can't get one,
* we will try to overlay planes (GLX_LEVEL 1)
*/
static int al2[] = {GLX_LEVEL, 2, None };
static int al3[] = {GLX_LEVEL, 1, None };
/*
* a convenience function, just waits for the window to map. this
* is handy, since we don't want to risk OpenGL drawing into an
* unmapped window, that would be bad...
*/
static Bool WaitForNotify (Display *d, XEvent *e, char *arg)
{
return (e->type == MapNotify) && (e->xmap.window == (Window) arg);
}
/*
* default window size...
*/
#define WINSIZE 600
/*
* a few global variables
*/
int WIRE_FRAME = 0;
int TRANSPARENT = 0;
int RESET = True;
int WHITE_PIXEL_NUM;
int xorigin, yorigin; /* window x and y locations */
unsigned int width, height; /* window width and height */
float rx, ry; /* adjusted x and y locations */
Display *dpy; /* X Display */
Window win; /* OpenGL X Window ID */
Window owin; /* OpenGL overlay X Window ID */
GLXContext cx; /* context for the OpenGL window */
GLXContext ocx; /* context for the overlay OpenGL window */
Window winList[3]; /* X window ID list, needed to map window
colormaps */
/*
* main routine.
*/
main()
{
XVisualInfo *vi; /* X Visual */
Colormap cmap, ocmap; /* X Colormap */
XSetWindowAttributes swa; /* X Window Attributes */
XEvent event; /* X event */
char xbuf[20]; /* character buffer */
int nchar = 20; /* size of character buffer */
KeySym key; /* keyboard key hit */
XComposeStatus cs; /* X keyboard compose structure */
XWindowAttributes winattrs; /* X Window attribute structure */
XColor spix, pixel; /* X pixel structure */
float fx, fy; /* adjusted x & y cursor positions */
/*
* open a connection to the local display
*/
dpy = XOpenDisplay (0);
/*
* get an OpenGL main plane visual, if we fail, big problems,
* exit...
*/
if (!(vi = glXChooseVisual(dpy, DefaultScreen(dpy), attributeList))) {
printf("\n can't get requested visual type, bye...\n");
exit(0);
}
/* create a GLX context */
cx = (GLXContext) glXCreateContext (dpy, vi, None, GL_TRUE);
/* create a colormap using this visual */
cmap = XCreateColormap (dpy, RootWindow(dpy, vi->screen), vi->visual,
AllocNone);
/* set up the window attributes and create an X Window */
swa.colormap = cmap;
swa.border_pixel = 1;
swa.event_mask = StructureNotifyMask;
win = XCreateWindow (dpy, RootWindow(dpy,vi->screen),
0, 0, WINSIZE, WINSIZE,
0, vi->depth, InputOutput, vi->visual,
CWBorderPixel|CWColormap|CWEventMask, &swa);
XMapWindow (dpy,win);
/*
* try to create an overlay window. first try for GLX_LEVEL 2, a visual
* in the overlay planes. if that fails, go for GLX_LEVEL 1, a visual in
* the popup planes. if that fails, game over...
*/
if (!(vi = glXChooseVisual (dpy, DefaultScreen(dpy), al2))) {
/*
* overlay failed, try popup
*/
fprintf(stderr, "bummer, can't get overlay visual, trying popup...\n");
if (!(vi = glXChooseVisual (dpy, DefaultScreen(dpy), al3))) {
/*
* popup failed too, bummer
*/
fprintf(stderr,
"bummer, can't get requested popup visual either, bye...\n");
exit(0);
}
else { /* got popup visual! */
fprintf(stderr,"got popup visual!\n");
}
}
else {
fprintf(stderr, "got overlay visual!\n");
}
/*
* create a GLX context for the overlay window
*/
ocx = (GLXContext) glXCreateContext (dpy, vi, None, GL_TRUE);
/*
* create a colormap using this visual
*/
ocmap = XCreateColormap (dpy, RootWindow(dpy, vi->screen), vi->visual,
AllocNone);
/*
* set up window attributes and create a X Window with overlay visual
*/
swa.colormap = ocmap;
swa.border_pixel = 0;
swa.win_gravity = UnmapGravity;
swa.bit_gravity = NorthWestGravity;
swa.background_pixel = BlackPixel(dpy, vi->screen);
owin = XCreateWindow (dpy, win, 0, 0, WINSIZE, WINSIZE,
0, vi->depth, InputOutput, vi->visual,
CWBorderPixel|CWColormap|CWEventMask, &swa);
/*
* map window
*/
XMapWindow (dpy,owin);
/*
* wait for main planes window to map so that we can start drawing into
* it.
*/
XIfEvent(dpy, &event, WaitForNotify, (char *) win);
/*
* install the colormap windows property so that overlay colormap
* takes hold when we move cursor into window
*/
winList[0] = win;
winList[1] = owin;
XSetWMColormapWindows(dpy, win, winList, 2);
/*
* get the 'white' pixel value, we will need this
* to set colormap index for overlay drawing
*/
XAllocNamedColor(dpy, ocmap, "white", &spix, &pixel);
WHITE_PIXEL_NUM = pixel.pixel;
/*
* connect the context to the main planes window
*/
if (!glXMakeCurrent(dpy, win, cx) == GL_TRUE) {
return 0;
}
/*
* get the window size and location so that we can
* make the cylinder track the mouse movements *somewhat* acurately
*/
XGetWindowAttributes(dpy, win, &winattrs);
xorigin = winattrs.x;
yorigin = winattrs.y;
width = winattrs.width;
height = winattrs.height;
/*
* all right! finally some OpenGL stuff!!
* enable zbuffer depth test
*/
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
/*
* set up projection matrix, perspective projection if you please...
*/
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective((double) 450, (double) (width/(float)height),
(double) .25, (double) 15.0);
/*
* ok, model transformations from now on...
*/
glMatrixMode(GL_MODELVIEW);
/*
* set up lighting attributes
*/
glLightfv(GL_LIGHT1, GL_POSITION, lpos);
glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse);
glLightfv(GL_LIGHT1, GL_SPECULAR, specular);
/*
* set up light model attributes
*/
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, 1);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, alm);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
/*
* turn on the light!
*/
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT1);
/*
* hit the model matrix with an initial translation, 3 units back in
* Z direction to add a little spice...
*/
glTranslatef(0., 0., -3.);
/*
* set X input stuff
*/
XSelectInput(dpy, win, ExposureMask);
XSelectInput(dpy, win, ExposureMask |StructureNotifyMask |
ButtonPressMask | Button1MotionMask |
SubstructureNotifyMask | KeyPressMask |
KeyReleaseMask | ButtonReleaseMask );
/*
* do the same for overlay window
*/
XSelectInput(dpy, owin, ExposureMask);
XSelectInput(dpy, owin, ExposureMask |StructureNotifyMask |
ButtonPressMask | Button1MotionMask |
SubstructureNotifyMask | KeyPressMask |
KeyReleaseMask | ButtonReleaseMask );
/*
* ready to go, print out instructions to the screen
*/
printf("\npush leftmouse button and drag to move cylinder!\n");
printf("\n 'o' key to toggle overlay drawing");
printf("\n 't' key to toggle scene transparency");
printf("\n 'Esc' key to quit\n");
fflush(stdout);
/*
* the dreaded X event loop...
*/
while (1) { /* loop forever... */
XNextEvent(dpy, &event);
switch (event.type) {
case Expose:
if (event.xexpose.count)
continue;
drawScene();
if (!WIRE_FRAME) { /* have to manually clear overlay */
/* since code is too 'dumb' to */
/* redraw overlay in drawScene */
glXMakeCurrent(dpy, owin, ocx);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
break;
case ConfigureNotify:
/*
* resize or reposition, so get pertinent window
* info and update scene. don't forget to
* resize overlay window!
*/
XGetWindowAttributes(dpy, win, &winattrs);
xorigin = winattrs.x;
yorigin = winattrs.y;
width = winattrs.width;
height = winattrs.height;
glXMakeCurrent(dpy, win, cx);
glViewport(0, 0, width, height);
drawScene();
XResizeWindow(dpy, owin, width, height);
glXMakeCurrent(dpy, owin, ocx);
glViewport(0, 0, width, height);
break;
case KeyPress:
XLookupString((XKeyEvent *) &event, xbuf, nchar, &key, &cs);
switch (key) {
case XK_Escape: /* quit */
printf("\n bye...\n");
exit(0);
break;
case XK_T: /* toggle scene transparency */
case XK_t:
TRANSPARENT = !TRANSPARENT;
drawScene();
break;
case XK_O: /* toggle overlay drawing */
case XK_o:
WIRE_FRAME = !WIRE_FRAME;
drawScene();
break;
}
break;
case MotionNotify:
/*
* get cursor position and rotate scene
*/
fx = (float) event.xmotion.x;
fy = (float) event.xmotion.y;
rx = -500.0 * (2.0*(fy - yorigin)/height-1.0);
ry = 500.0 * (2.0*(fx - xorigin)/width-1.0);
drawScene();
break;
default:
break;
}
}
}
/*
* main scene drawing routine.
*/
void
drawScene()
{
if (!WIRE_FRAME) {
/*
* no wire frame, so update main planes scene.
* set the main plane window as the current window to draw into,
* clear the window and depth buffer
*/
glXMakeCurrent(dpy, win, cx);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/*
* push down a new matrix onto the matrix stack. then apply
* a couple of rotations
*/
glPushMatrix();
glRotatef((float) ry, 0., 1., 0.);
glRotatef((float) -rx, 1., 0., 0.);
/*
* disable blending and turn on depth check
*/
glDisable(GL_BLEND);
glBlendFunc(GL_ONE, GL_ZERO);
glDepthMask(1);
/*
* set up materials
*/
setMaterial(GL_FRONT, ambient2, diffuse2, specular2, shininess);
setMaterial(GL_BACK, bamat, bdmat, bsmat, shin);
/*
* scale down cylinder slightly
*/
glScalef(.5, 1.0, .5);
drawcyl();
/*
* pop matrix off of stack
*/
glPopMatrix();
/*
* new matrix, apply same rotations
*/
glPushMatrix();
glRotatef((float) ry, 0., 1., 0.);
glRotatef((float) -rx, 1., 0., 0.);
/*
* if transparency enabled, turn off depth check, enable blending
*/
if (TRANSPARENT) {
glDepthMask(0);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
else { /* else no transparency */
glDisable(GL_BLEND);
glDepthMask(1);
}
/*
* set up materials, draw cylinder
*/
setMaterial(GL_FRONT, amat, dmat, smat, shin);
setMaterial(GL_BACK, amat, dmat, smat, shin);
drawcyl();
/*
* disable blending
*/
if (TRANSPARENT)
glDisable(GL_BLEND);
/*
* pop off matrix, swap buffers to show updated scene
*/
glPopMatrix();
glXSwapBuffers(dpy, win);
}
else {
/*
* draw into overlay window. make overlay window current, and
* clear;
*/
glXMakeCurrent(dpy, owin, ocx);
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
/*
* push down a matrix onto the stack, and apply rotations
*/
glPushMatrix();
glRotatef((float) ry, 0., 1., 0.);
glRotatef((float) -rx, 1., 0., 0.);
/*
* draw the wire box, flush the graphics pipe, pop the matrix off
* of the matrix stack
*/
drawBox();
glFlush();
glPopMatrix();
}
}
/*
* routine to draw cylinder. note that normals are specified with
* glNormal3fv() to take advantage of lighting.
*/
void
drawcyl()
{
double dy = .2;
double theta, dtheta = 2*M_PI/20;
double x, y, z;
float n[3], v[3];
int i, j;
for (i = 0, y = -1; i < 10; i++, y += dy) {
glEnable(GL_LIGHTING);
glBegin(GL_TRIANGLE_STRIP);
for (j = 0, theta = 0; j <= 20; j++, theta += dtheta) {
if (j == 20) theta = 0;
x = cos(theta);
z = sin(theta);
n[0] = x; n[1] = 0; n[2] = z;
glNormal3fv(n);
v[0] = x; v[1] = y; v[2] = z;
glVertex3fv(v);
v[1] = y + dy;
glVertex3fv(v);
}
glEnd();
}
}
/*
* convenience function to set material properties
*/
void
setMaterial(GLenum face, float *ambient, float *diffuse,
float *specular, float *shininess)
{
glMaterialfv(face, GL_AMBIENT, ambient);
glMaterialfv(face, GL_DIFFUSE, diffuse);
glMaterialfv(face, GL_SPECULAR, specular);
glMaterialfv(face, GL_SHININESS, shininess);
}
/*
* routine to draw the wire box in the overlay window. notice that
* we use color index mode, glIndexi() to set colors here even though
* the main plane window uses RGB
*/
void
drawBox()
{
float v[2];
glIndexi(WHITE_PIXEL_NUM);
glBegin(GL_LINE_LOOP);
v[0] = v[1] = -.5;
glVertex2fv(v);
v[0] = .5;
glVertex2fv(v);
v[1] = .5;
glVertex2fv(v);
v[0] = -.5;
glVertex2fv(v);
glEnd();
}